package com.eyun.service;

import cn.hutool.core.bean.BeanUtil;
import com.eyun.domain.RegionCode;
import com.eyun.repository.RegionCodeRepository;
import com.eyun.service.dto.RegionCodeDTO;
import com.eyun.service.mapper.RegionCodeMapper;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.CacheManager;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

// jhipster-needle-add-import - JHipster will add getters and setters here, do not remove

/**
 * Service Implementation for managing {@link RegionCode}.
 */
@Service
@Transactional
public class RegionCodeService {

    private final Logger log = LoggerFactory.getLogger(RegionCodeService.class);
    private final List<String> relationCacheNames = Arrays.asList(
        com.eyun.domain.RegionCode.class.getName() + ".parent",
        com.eyun.domain.RegionCode.class.getName() + ".children"
    );

    private final RegionCodeRepository regionCodeRepository;

    private final CacheManager cacheManager;

    private final RegionCodeMapper regionCodeMapper;

    public RegionCodeService(RegionCodeRepository regionCodeRepository, CacheManager cacheManager, RegionCodeMapper regionCodeMapper) {
        this.regionCodeRepository = regionCodeRepository;
        this.cacheManager = cacheManager;
        this.regionCodeMapper = regionCodeMapper;
    }

    /**
     * Save a regionCode.
     *
     * @param regionCodeDTO the entity to save.
     * @return the persisted entity.
     */
    public RegionCodeDTO save(RegionCodeDTO regionCodeDTO) {
        log.debug("Request to save RegionCode : {}", regionCodeDTO);
        RegionCode regionCode = regionCodeMapper.toEntity(regionCodeDTO);
        clearChildrenCache();
        regionCode = regionCodeRepository.save(regionCode);
        // 更新缓存
        if (regionCode.getParent() != null) {
            regionCode.getParent().addChildren(regionCode);
        }
        return regionCodeMapper.toDto(regionCode);
    }

    /**
     * Partially update a regionCode.
     *
     * @param regionCodeDTO the entity to update partially.
     * @return the persisted entity.
     */
    public Optional<RegionCodeDTO> partialUpdate(RegionCodeDTO regionCodeDTO) {
        log.debug("Request to partially update RegionCode : {}", regionCodeDTO);

        return regionCodeRepository
            .findById(regionCodeDTO.getId())
            .map(
                existingRegionCode -> {
                    regionCodeMapper.partialUpdate(existingRegionCode, regionCodeDTO);

                    return existingRegionCode;
                }
            )
            .map(regionCodeRepository::save)
            .map(regionCodeMapper::toDto);
    }

    /**
     * Get all the regionCodes.
     *
     * @param pageable the pagination information.
     * @return the list of entities.
     */
    @Transactional(readOnly = true)
    public Page<RegionCodeDTO> findAll(Pageable pageable) {
        log.debug("Request to get all RegionCodes");
        return regionCodeRepository.findAll(pageable).map(regionCodeMapper::toDto);
    }

    /**
     * Get all the regionCodes for parent is null.
     *
     * @param pageable the pagination information
     * @return the list of entities
     */
    @Transactional
    public Page<RegionCodeDTO> findAllTop(Pageable pageable) {
        log.debug("Request to get all RegionCodes for parent is null");
        return regionCodeRepository.findAllByParentIsNull(pageable).map(regionCodeMapper::toDto);
    }

    /**
     * Get all the regionCodes for parent is parentId.
     *
     * @param parentId the Id of parent
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<RegionCodeDTO> findChildrenByParentId(Long parentId) {
        log.debug("Request to get all RegionCodes for parent is parentId");
        return regionCodeRepository.findAllByParentId(parentId, Pageable.unpaged()).map(regionCodeMapper::toDto).getContent();
    }

    /**
     * count all the regionCodes.
     * @return the count of entities
     */
    @Transactional(readOnly = true)
    public long count() {
        log.debug("Request to count all RegionCodes");
        return regionCodeRepository.count();
    }

    /**
     * Get one regionCode by id.
     *
     * @param id the id of the entity.
     * @return the entity.
     */
    @Transactional(readOnly = true)
    public Optional<RegionCodeDTO> findOne(Long id) {
        log.debug("Request to get RegionCode : {}", id);
        return regionCodeRepository.findById(id).map(regionCodeMapper::toDto);
    }

    /**
     * Get one regionCode by example.
     *
     * @param example the example of the entity.
     * @return the entity.
     */
    @Transactional(readOnly = true)
    public Optional<RegionCodeDTO> findOneByExample(Example<RegionCode> example) {
        log.debug("Request to get RegionCode by example");
        return regionCodeRepository.findOne(example).map(regionCodeMapper::toDto);
    }

    /**
     * Get all the regionCodes by example.
     *
     * @param example the example of the entity.
     * @return the entities.
     */
    @Transactional(readOnly = true)
    public Page<RegionCodeDTO> findAllByExample(Example<RegionCode> example, Pageable pageable) {
        log.debug("Request to get RegionCode by example");
        return regionCodeRepository.findAll(example, pageable).map(regionCodeMapper::toDto);
    }

    /**
     * Delete the regionCode by id.
     *
     * @param id the id of the entity.
     */
    public void delete(Long id) {
        log.debug("Request to delete RegionCode : {}", id);
        RegionCode regionCode = regionCodeRepository.getOne(id);
        if (regionCode.getParent() != null) {
            regionCode.getParent().removeChildren(regionCode);
        }
        if (regionCode.getChildren() != null) {
            regionCode
                .getChildren()
                .forEach(
                    subRegionCode -> {
                        subRegionCode.setParent(null);
                    }
                );
        }
        regionCodeRepository.deleteById(id);
    }

    /**
     * Update ignore specified fields by regionCode
     */
    public RegionCodeDTO updateByIgnoreSpecifiedFields(RegionCodeDTO changeRegionCodeDTO, Set<String> unchangedFields) {
        RegionCodeDTO regionCodeDTO = findOne(changeRegionCodeDTO.getId()).get();
        BeanUtil.copyProperties(changeRegionCodeDTO, regionCodeDTO, unchangedFields.toArray(new String[0]));
        regionCodeDTO = save(regionCodeDTO);
        return regionCodeDTO;
    }

    /**
     * Update specified fields by regionCode
     */
    public RegionCodeDTO updateBySpecifiedFields(RegionCodeDTO changeRegionCodeDTO, Set<String> fieldNames) {
        RegionCodeDTO regionCodeDTO = findOne(changeRegionCodeDTO.getId()).get();
        RegionCodeDTO finalRegionCodeDTO = regionCodeDTO;
        fieldNames.forEach(
            fieldName -> {
                BeanUtil.setFieldValue(finalRegionCodeDTO, fieldName, BeanUtil.getFieldValue(changeRegionCodeDTO, fieldName));
            }
        );
        regionCodeDTO = save(finalRegionCodeDTO);
        return regionCodeDTO;
    }

    /**
     * Update specified field by regionCode
     */
    public RegionCodeDTO updateBySpecifiedField(RegionCodeDTO changeRegionCodeDTO, String fieldName) {
        RegionCodeDTO regionCodeDTO = findOne(changeRegionCodeDTO.getId()).get();
        BeanUtil.setFieldValue(regionCodeDTO, fieldName, BeanUtil.getFieldValue(changeRegionCodeDTO, fieldName));
        regionCodeDTO = save(regionCodeDTO);
        return regionCodeDTO;
    }

    // 清除children缓存
    private void clearChildrenCache() {
        Objects.requireNonNull(cacheManager.getCache(com.eyun.domain.RegionCode.class.getName() + ".children")).clear();
    }

    private void clearRelationsCache() {
        this.relationCacheNames.forEach(
                cacheName -> {
                    if (cacheManager.getCache(cacheName) != null) {
                        cacheManager.getCache(cacheName).clear();
                    }
                }
            );
    }
    // jhipster-needle-service-add-method - JHipster will add getters and setters here, do not remove

}
